package pl.darbat.photogallery.list;

/* Based on SimpleAdapter 2.1 */


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import pl.darbat.photogallery.Debug;
import pl.darbat.photogallery.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

	public class PhotoListAdapter extends BaseAdapter implements Filterable, OnScrollListener {
	    private static final String TAG = null;
		private int[] mTo;
	    private String[] mFrom;
	    private ViewBinder mViewBinder;

	    private List<? extends Map<String, ?>> mData;

	    private ListDownloader<String, Bitmap> mImageDownloader;
	    private DownloadAction<String, Bitmap> mImageDownload;
	    
	    private Bitmap mPlaceHolder;
	    
	    private int mResource;
	    private int mDropDownResource;
	    private LayoutInflater mInflater;
	    private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
	    
	    private SimpleFilter mFilter;
	    private ArrayList<Map<String, ?>> mUnfilteredData;
		private boolean mScrolling = false;


	    public PhotoListAdapter(Context context, List<? extends Map<String, ?>> data,
	            int layoutResource, String[] from, int[] to, int placeHolder, int cacheSize) {
	        mData = data;
	        mResource = mDropDownResource = layoutResource;
	        mFrom = from;
	        mTo = to;
	        
	        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	        mImageDownload = new ImageDownload(context, R.anim.slow_fade_in);
	        mImageDownloader = new ListDownloader<String, Bitmap>(mImageDownload, cacheSize);

	        mPlaceHolder = ((BitmapDrawable)context.getResources().getDrawable(placeHolder)).getBitmap();
	    }
	    
	    
	    
	    
	    public void cleanUp(){
	    	mImageDownloader.clearCache();
	    	mHolders.clear();
	    }

	    public int getCount() {
	        return mData.size();
	    }


	    public Object getItem(int position) {
	        return mData.get(position);
	    }


	    public long getItemId(int position) {
	        return position;
	    }


	    public View getView(int position, View convertView, ViewGroup parent) {
	        return createViewFromResource(position, convertView, parent, mResource);
	    }

	    private View createViewFromResource(int position, View convertView,
	            ViewGroup parent, int resource) {
	        View v;
	        if (convertView == null) {
	            v = mInflater.inflate(resource, parent, false);

	            final int[] to = mTo;
	            final int count = to.length;
	            final View[] holder = new View[count];

	            for (int i = 0; i < count; i++) {
	                holder[i] = v.findViewById(to[i]);
	            }

	            mHolders.put(v, holder);
	        } else {
	            v = convertView;
	        }

	        bindView(position, v);

	        return v;
	    }


	    public void setDropDownViewResource(int resource) {
	        this.mDropDownResource = resource;
	    }

	    @Override
	    public View getDropDownView(int position, View convertView, ViewGroup parent) {
	        return createViewFromResource(position, convertView, parent, mDropDownResource);
	    }

	    private void bindView(int position, View view) {
	        final Map dataSet = mData.get(position);
	        if (dataSet == null) {
	            return;
	        }

	        final ViewBinder binder = mViewBinder;
	        final View[] holder = mHolders.get(view);
	        final String[] from = mFrom;
	        final int[] to = mTo;
	        final int count = to.length;

	        for (int i = 0; i < count; i++) {
	            final View v = holder[i];
	            if (v != null) {
	                final Object data = dataSet.get(from[i]);
	                String text = data == null ? "" : data.toString();
	                if (text == null) {
	                    text = "";
	                }

	                boolean bound = false;
	                if (binder != null) {
	                    bound = binder.setViewValue(v, data, text);
	                }

	                if (!bound) {
	                	if (v instanceof TextView) {
	                        setViewText((TextView) v, text);
	                    } else if (v instanceof ImageView) {
	                        if (data instanceof Integer) {
	                            setViewImage((ImageView) v, (Integer) data);                            
	                        } else {
	                            setViewImage((ImageView) v, text);
	                        }
	                    } else {
	                        throw new IllegalStateException(v.getClass().getName() + " is not a " +
	                                " view that can be bounds by this PhotoListAdapter");
	                    }
	                }
	            }
	        }
	    }

	    public ViewBinder getViewBinder() {
	        return mViewBinder;
	    }

	    public void setViewBinder(ViewBinder viewBinder) {
	        mViewBinder = viewBinder;
	    }

	    public void setViewImage(ImageView v, int value) {
	        v.setImageResource(value);
	    }

	    public void setViewImage(ImageView v, String link) {
	    	v.setTag(link);
	    	
	    	if(!mScrolling){
	    		mImageDownloader.downloadWithCache(link, v, mPlaceHolder);
	    	} else {
	    		mImageDownloader.getFromCache(link, v, mPlaceHolder);
	    	}
	    }

	    public void setViewText(TextView v, String text) {
	        v.setText(text);
	    }

	    public Filter getFilter() {
	        if (mFilter == null) {
	            mFilter = new SimpleFilter();
	        }
	        return mFilter;
	    }

	    public static interface ViewBinder {
	        /**
	         * Binds the specified data to the specified view.
	         *
	         * When binding is handled by this ViewBinder, this method must return true.
	         * If this method returns false, SimpleAdapter will attempts to handle
	         * the binding on its own.
	         *
	         * @param view the view to bind the data to
	         * @param data the data to bind to the view
	         * @param textRepresentation a safe String representation of the supplied data:
	         *        it is either the result of data.toString() or an empty String but it
	         *        is never null
	         *
	         * @return true if the data was bound to the view, false otherwise
	         */
	        boolean setViewValue(View view, Object data, String textRepresentation);
	    }

	    /**
	     * <p>An array filters constrains the content of the array adapter with
	     * a prefix. Each item that does not start with the supplied prefix
	     * is removed from the list.</p>
	     */
	    private class SimpleFilter extends Filter {

	        @Override
	        protected FilterResults performFiltering(CharSequence prefix) {
	            FilterResults results = new FilterResults();

	            if (mUnfilteredData == null) {
	                mUnfilteredData = new ArrayList<Map<String, ?>>(mData);
	            }

	            if (prefix == null || prefix.length() == 0) {
	                ArrayList<Map<String, ?>> list = mUnfilteredData;
	                results.values = list;
	                results.count = list.size();
	            } else {
	                String prefixString = prefix.toString().toLowerCase();

	                ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
	                int count = unfilteredValues.size();

	                ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(count);

	                for (int i = 0; i < count; i++) {
	                    Map<String, ?> h = unfilteredValues.get(i);
	                    if (h != null) {
	                        
	                        int len = mTo.length;

	                        for (int j=0; j<len; j++) {
	                            String str =  (String)h.get(mFrom[j]);
	                            
	                            String[] words = str.split(" ");
	                            int wordCount = words.length;
	                            
	                            for (int k = 0; k < wordCount; k++) {
	                                String word = words[k];
	                                
	                                if (word.toLowerCase().startsWith(prefixString)) {
	                                    newValues.add(h);
	                                    break;
	                                }
	                            }
	                        }
	                    }
	                }

	                results.values = newValues;
	                results.count = newValues.size();
	            }

	            return results;
	        }

	        @Override
	        protected void publishResults(CharSequence constraint, FilterResults results) {
	            //noinspection unchecked
	            mData = (List<Map<String, ?>>) results.values;
	            if (results.count > 0) {
	                notifyDataSetChanged();
	            } else {
	                notifyDataSetInvalidated();
	            }
	        }
	    }

		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
			// TODO Auto-generated method stub
			
		}


		public void onScrollStateChanged(AbsListView absListView, int scrollState) {
	        switch (scrollState) {
	        case OnScrollListener.SCROLL_STATE_IDLE:
	            mScrolling = false;
	            if(Debug.PHOTOLISTADAPTER) Log.v(TAG,"SCROLL_STATE_IDLE");
	            int howMany = absListView.getChildCount();
	            for (int i = 0; i < howMany; i++) {
	                View view = absListView.getChildAt(i);
	                if (view != null) {
	                	ImageView imageview = null;
	                	String link = null;
	                	
	                	View[] viewHolder = mHolders.get(view);
	                	if(viewHolder!=null){
	                		for(int j=0; j<viewHolder.length; j++){
	                			if(viewHolder[j] instanceof ImageView){
	                				imageview = (ImageView) viewHolder[j];
	                				Object linkHolder = imageview.getTag();
	                				if(linkHolder!=null && linkHolder instanceof String){
	                					link = (String) linkHolder;
	                				}
	                			} 
	                		}
	                		if(imageview != null && link != null){
	                			//if(Debug.PHOTOLISTADAPTER) Log.v(TAG,"Slow Adapter: downloading image: " + link);
	                			mImageDownloader.downloadWithCache(link, imageview, mPlaceHolder);
	                		}
	                	}
	                }
	            }
	            break;
	        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
	        	if(Debug.PHOTOLISTADAPTER) Log.v(TAG, "SCROLL_STATE_TOUCH_SCROLL");
	            mScrolling = false;
	            break;
	        case OnScrollListener.SCROLL_STATE_FLING:
	        	if(Debug.PHOTOLISTADAPTER) Log.v(TAG, "SCROLL_STATE_FLING");
	            mScrolling = true;
	            break;
	        }
			
		}
	}


